package com.lingyuan.oms.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingyuan.common.core.domain.R;
import com.lingyuan.common.core.domain.vo.cart.CartItemVo;
import com.lingyuan.common.core.domain.vo.sms.ComputeVo;
import com.lingyuan.common.core.domain.vo.sms.CouponMemberVo;
import com.lingyuan.common.core.domain.vo.sms.CouponSkuIdsVo;
import com.lingyuan.common.core.domain.vo.sms.UpdateCouponHistoryParam;
import com.lingyuan.common.core.domain.vo.ums.MemberAddressVo;
import com.lingyuan.common.core.domain.vo.ums.MemberVo;
import com.lingyuan.common.core.exception.ServiceException;
import com.lingyuan.common.core.utils.StringUtils;
import com.lingyuan.oms.constant.CartConstant;
import com.lingyuan.oms.constant.OrderConstant;
import com.lingyuan.oms.constant.OrderStatusEnum;
import com.lingyuan.oms.domain.OrderEntity;
import com.lingyuan.oms.domain.PaymentInfoEntity;
import com.lingyuan.oms.domain.param.CreateOrderParam;
import com.lingyuan.oms.domain.param.SettleAccountsParam;
import com.lingyuan.oms.domain.request.OrderSyncRequest;
import com.lingyuan.oms.domain.response.SettleAccountsResponse;
import com.lingyuan.oms.mapper.OrderMapper;
import com.lingyuan.oms.remote.CouponRemoteService;
import com.lingyuan.oms.remote.ProductRemoteService;
import com.lingyuan.oms.remote.UmsRemoteService;
import com.lingyuan.oms.remote.WarehouseRemoteService;
import com.lingyuan.oms.service.OrderItemService;
import com.lingyuan.oms.service.OrderService;
import com.lingyuan.oms.service.PaymentInfoService;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;


/**
 * @ClassName：OrderServiceImpl
 * @Author: LeiHao
 * @Date: 2024/9/18 10:16
 * @Description: 订单业务实现
 */
@Service
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements OrderService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UmsRemoteService umsRemoteService;
    @Autowired
    private WarehouseRemoteService warehouseRemoteService;
    @Autowired
    private ProductRemoteService productRemoteService;
    @Autowired
    private CouponRemoteService couponRemoteService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private ThreadPoolTaskExecutor orderExecutor;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    /**
     * 最大任务数
     **/
    public static int MAX_TASK_NUM = 1000;
    private final Queue<OrderSyncRequest> queue = new LinkedBlockingQueue<>();

    @PostConstruct
    public void init() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(this::processQueue, 100, 800, TimeUnit.MILLISECONDS);
    }

    private void processQueue() {
        int size = queue.size();
        if (size == 0) {
            return;
        }
        List<OrderSyncRequest> list = new ArrayList<>();
        System.out.println("合并了 [" + size + "] 个请求");
        for (int i = 0; i < size; i++) {
            if (i < MAX_TASK_NUM) {
                list.add(queue.poll());
            }
        }
        List<OrderSyncRequest> userReqs = new ArrayList<>(list);
        boolean response = this.queryOrderBatchAdd(userReqs);
        for (OrderSyncRequest request : list) {
            request.getCompletableFuture().complete(response);
        }
    }

    @Transactional
    public Boolean queryOrderBatchAdd(List<OrderSyncRequest> userReqs) {
        SqlSession sqlSession = null;
        try {
            sqlSession = sqlSessionFactory.openSession();
            OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
            List<OrderEntity> orderEntityList = userReqs.stream()
                    .map(OrderSyncRequest::getOrderEntity)
                    .collect(Collectors.toList());
            int i=  orderMapper.insertOrderList(orderEntityList);
            sqlSession.commit();
            if (i==0){
                return false;
            }
            return true;
        } catch (Exception e) {
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
        return false;
    }

    @Override
    public void syncRedisOrder(String orderSn) {
        // 查询订单
        if (!stringRedisTemplate.hasKey(OrderConstant.SUBMIT_ORDER_KEY + orderSn)) {
            throw new ServiceException("订单不存在");
        }
        String orderStr = stringRedisTemplate.opsForValue().get(OrderConstant.SUBMIT_ORDER_KEY + orderSn);
        OrderEntity orderEntity = JSON.parseObject(orderStr, OrderEntity.class);
        //更新redis订单状态
        orderEntity.setSyncDb(1);
        stringRedisTemplate.opsForValue().set(OrderConstant.SUBMIT_ORDER_KEY + orderSn, JSON.toJSONString(orderEntity));
        OrderSyncRequest orderSyncRequest = new OrderSyncRequest();
        orderSyncRequest.setRequestId(UUID.randomUUID().toString());
        orderSyncRequest.setOrderEntity(orderEntity);
        CompletableFuture<Boolean> booleanCompletableFuture = new CompletableFuture<>();
        orderSyncRequest.setCompletableFuture(booleanCompletableFuture);
        // 将对象传入队列 ==> 等待其他请求合并后访问数据库
        queue.offer(orderSyncRequest);
        try {
            Boolean b = booleanCompletableFuture.get();
            if (b) {
                System.out.println("======================redis订单信息同步成功========================");
//                stringRedisTemplate.delete(OrderConstant.SUBMIT_ORDER_KEY + orderSn);
            } else {
                // TODO: 同步redis失败补偿
                orderEntity.setSyncDb(0);
                stringRedisTemplate.opsForValue().set(OrderConstant.SUBMIT_ORDER_KEY + orderSn, JSON.toJSONString(orderEntity));
            }
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt(); // Restore interrupted status
            throw new RuntimeException(e);
        }
    }

    @Override
    public OrderEntity getRedisOrder(String selectOrderToken) {
        String orderStr = stringRedisTemplate.opsForValue().get(OrderConstant.SUBMIT_ORDER_KEY + selectOrderToken);
        if (!StringUtils.isBlank(orderStr)) {
            OrderEntity orderEntity = JSON.parseObject(orderStr, OrderEntity.class);
            return orderEntity;
        }
        return null;
    }

    /* *
     * @Title: createOrder
     * @Author: DELL
     * @Date: 2024-09-21 11:50:25
     * @Params: [createOrderParam]
     * @Return: OrderEntity
     * @Description:  生成订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity createOrder(CreateOrderParam createOrderParam) {
        BigDecimal payAmount = new BigDecimal(createOrderParam.getPayAmount());
        BigDecimal freightAmount = new BigDecimal(createOrderParam.getFreightAmount());
        payAmount = payAmount.add(freightAmount);

//        Long userId = 1L;
        // 订单生成
        OrderEntity orderEntity = new OrderEntity();
        // 异步获取购物车中的商品信息
        CompletableFuture<List<CartItemVo>> cartItemsFuture = CompletableFuture.supplyAsync(() -> {
            String skuIds = createOrderParam.getSkuIds();
            List<String> skuIdList = Arrays.asList(skuIds.split(","));
            return skuIdList.stream().map(skuId -> {
                Object obj = stringRedisTemplate.boundHashOps(CartConstant.CART_REDIS_KEY + createOrderParam.getUserId()).get(skuId);
                return JSON.parseObject(obj.toString(), CartItemVo.class);
            }).collect(Collectors.toList());
        }, orderExecutor);

        // 异步获取用户信息和收货地址
        CompletableFuture<Void> userInfoAndAddressFuture = CompletableFuture.runAsync(() -> {
            // 订单号生成
            String orderSn = createOrderParam.getOrderSn();
            orderEntity.setOrderSn(orderSn);
            orderEntity.setMemberId(createOrderParam.getUserId());
            orderEntity.setMemberUsername(createOrderParam.getUserName());
            // 获取收货地址
            getAddress(createOrderParam.getUserId(), orderEntity);
        }, orderExecutor);

        // 合并异步任务
        CompletableFuture.allOf(cartItemsFuture, userInfoAndAddressFuture).join();
        List<CartItemVo> cartItemVoList = cartItemsFuture.join();

        // 总价格
        BigDecimal totalPrice = cartItemVoList.stream().map(CartItemVo::getTotalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        orderEntity.setCouponId(createOrderParam.getCouponId());
        orderEntity.setTotalAmount(totalPrice);

        // 优惠券计算
        ComputeVo computeVo = new ComputeVo();
        computeVo.setCouponId(createOrderParam.getCouponId());
        computeVo.setProductList(cartItemVoList);

        // 购买数量
        Integer payNum = cartItemVoList.stream().map(CartItemVo::getPayNum).reduce(0, Integer::sum);
        computeVo.setPayNum(payNum);

        if (createOrderParam.getCouponId() != null) {
            R<CouponSkuIdsVo> couponSkuIdsVoR = couponRemoteService.findCouponSkuIdsVo(computeVo);
            if (couponSkuIdsVoR.getCode() != 200) {
                throw new ServiceException("优惠券计算失败");
            }
            CouponSkuIdsVo couponSkuIdsVo = couponSkuIdsVoR.getData();
            BigDecimal payAmountPC = totalPrice.add(freightAmount).subtract(couponSkuIdsVo.getCouponPrice());
            if (payAmount.compareTo(payAmountPC) != 0) {
                throw new ServiceException("支付金额与实际支付金额不符");
            }
            orderEntity.setCouponAmount(couponSkuIdsVo.getCouponPrice());
            stringRedisTemplate.opsForValue().set(OrderConstant.ORDER_COUPON_KEY + orderEntity.getOrderSn(), JSON.toJSONString(couponSkuIdsVo.getSkuCouponPriceList()));
        }
        orderEntity.setPayAmount(payAmount);
        orderEntity.setFreightAmount(freightAmount);
        // 订单创建时间
        LocalDateTime now = LocalDateTime.now();
        orderEntity.setCreateTime(now);
        orderEntity.setStatus(OrderStatusEnum.UNPAID.getCode());
        //TODO 发消息到消息队列 订单信息存到redis 15分钟内支付完成 修改redis订单状态 定时器同步状态为已支付的订单信息到数据库
        stringRedisTemplate.opsForValue().set(OrderConstant.ORDER_CART_LIST_KEY + orderEntity.getOrderSn(), JSON.toJSONString(cartItemVoList));
        orderEntity.setSyncDb(0);
        return orderEntity;
    }


    /* *
     * @Params: [userId, orderEntity]
     * @Return: void
     * @Description: 获取收货地址
     */
    private void getAddress(Long userId, OrderEntity orderEntity) {
        R<MemberAddressVo> memberAddressVoR = umsRemoteService.findById(userId);
        if (memberAddressVoR.getCode() != 200) {
            throw new ServiceException("获取收货地址失败");
        }
        MemberAddressVo memberAddressVoRData = memberAddressVoR.getData();
        /**
         * 收货人姓名/电话/邮编/(省份/直辖市)/地区/详细地址
         */
        orderEntity.setReceiverName(memberAddressVoRData.getName());
        orderEntity.setReceiverPhone(memberAddressVoRData.getPhone());
        orderEntity.setReceiverPostCode(memberAddressVoRData.getPostCode());
        orderEntity.setReceiverProvince(memberAddressVoRData.getProvince());
        orderEntity.setReceiverCity(memberAddressVoRData.getCity());
        orderEntity.setReceiverRegion(memberAddressVoRData.getRegion());
        orderEntity.setReceiverDetailAddress(memberAddressVoRData.getDetailAddress());
    }

    /* *
     * @Title: settleAccounts
     * @Author: DELL
     * @Date: 2024-09-21 18:02:21
     * @Params: [settleAccountsParam]
     * @Return: SettleAccountsResponse
     * @Description: 结算
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SettleAccountsResponse settleAccounts(SettleAccountsParam settleAccountsParam) {
        Long userId = 1L;
        long startTime = System.currentTimeMillis();
        SettleAccountsResponse settleAccountsResponse = new SettleAccountsResponse();

        // 异步获取收货地址列表
        CompletableFuture<List<MemberAddressVo>> addressFuture = CompletableFuture.supplyAsync(() -> {
            R<List<MemberAddressVo>> memberAddressListR = umsRemoteService.findMemberByIdAddressList(userId);
            if (memberAddressListR.getCode() != 200) {
                throw new ServiceException("获取收货地址列表失败");
            }
            return memberAddressListR.getData();
        }, orderExecutor);

        // 异步获取购物车信息
        CompletableFuture<List<CartItemVo>> cartItemsFuture = CompletableFuture.supplyAsync(() -> {
            List<Object> values = stringRedisTemplate.boundHashOps(CartConstant.CART_REDIS_KEY + userId).values();
            if (settleAccountsParam.getSkuIds() == null || "".equals(settleAccountsParam.getSkuIds())) {
                throw new ServiceException("请选择要购买的商品");
            }
            List<String> skuIds = Arrays.stream(settleAccountsParam.getSkuIds().split(",")).map(String::toString).collect(Collectors.toList());
            return values.stream()
                    .map(obj -> JSON.parseObject(obj.toString(), CartItemVo.class))
                    .filter(cartItemVo -> skuIds.contains(cartItemVo.getProductId().toString()))
                    .collect(Collectors.toList());
        }, orderExecutor);

        // 异步获取会员信息
        CompletableFuture<MemberVo> memberFuture = CompletableFuture.supplyAsync(() -> {
            R<MemberVo> byUserIdR = umsRemoteService.findMemberById(userId);
            if (byUserIdR.getCode() != 200) {
                throw new ServiceException("获取会员信息失败");
            }
            return byUserIdR.getData();
        }, orderExecutor);

        // 异步获取优惠券信息
        CompletableFuture<List<CouponMemberVo>> couponFuture = CompletableFuture.supplyAsync(() -> {
            R<List<CouponMemberVo>> skuMinPrice = couponRemoteService.findSkuMinPrice(settleAccountsParam.getSkuIds());
            if (skuMinPrice.getCode() != 200) {
                throw new ServiceException("获取优惠券信息失败");
            }
            return skuMinPrice.getData();
        }, orderExecutor);

        // 合并所有异步结果
        CompletableFuture.allOf(addressFuture, cartItemsFuture, memberFuture, couponFuture).join();

        List<MemberAddressVo> memberAddressList = addressFuture.join();
        List<CartItemVo> cartItemVoList = cartItemsFuture.join();
        MemberVo memberVo = memberFuture.join();
        List<CouponMemberVo> skuMinPriceData = couponFuture.join();

        // 设置响应对象
        settleAccountsResponse.setAddressVoList(memberAddressList);
        settleAccountsResponse.setCartItemVoList(cartItemVoList);

        // 计算总价
        BigDecimal totalPrice = cartItemVoList.stream().map(CartItemVo::getTotalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (totalPrice.compareTo(settleAccountsParam.getTotalPrice()) != 0) {
            throw new ServiceException("结算金额有误");
        }
        settleAccountsResponse.setTotalPrice(totalPrice);

        // 计算购买总数
        Integer payNumber = cartItemVoList.stream().map(CartItemVo::getPayNum).reduce(0, Integer::sum);

        // 异步处理优惠券信息
        CompletableFuture<Void> processCouponsFuture = CompletableFuture.runAsync(() -> {
            for (CouponMemberVo couponMemberVo : skuMinPriceData) {
                if (couponMemberVo.getStatus() == 1) {
                    settleAccountsResponse.setCouponId(couponMemberVo.getId());

                    ComputeVo computeVo = new ComputeVo();
                    computeVo.setPayNum(payNumber);
                    computeVo.setProductList(cartItemVoList);
                    computeVo.setCouponId(couponMemberVo.getId());

                    R<CouponSkuIdsVo> couponSkuIdsVoR = couponRemoteService.findCouponSkuIdsVo(computeVo);
                    if (couponSkuIdsVoR.getCode() != 200) {
                        throw new ServiceException("获取优惠券信息失败");
                    }
                    CouponSkuIdsVo couponSkuIdsVoData = couponSkuIdsVoR.getData();
                    settleAccountsResponse.setCouponPrice(couponSkuIdsVoData.getCouponPrice());
                    settleAccountsResponse.setPayPrice(couponSkuIdsVoData.getTotalPrice());
                }
            }
        }, orderExecutor);

        // 等待优惠券处理完成
        processCouponsFuture.join();

        settleAccountsResponse.setPayNumber(payNumber);
        settleAccountsResponse.setCouponVoList(skuMinPriceData);
        settleAccountsResponse.setMemberVo(memberVo);

        // 生成下单 token
        String token = UUID.randomUUID().toString();
        stringRedisTemplate.opsForValue().set(OrderConstant.CONFIRM_THE_ORDER + token, "下单token", 5, TimeUnit.MINUTES);
        settleAccountsResponse.setToken(token);

        long endTime = System.currentTimeMillis();
        System.out.println("===========================================结算页面耗时:" + (endTime - startTime) + "ms========================================");

        return settleAccountsResponse;

    }

    /**
     * 通过订单id查询订单
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderEntity findOrderId(Long orderId) {
        return baseMapper.selectById(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payOrder(String outTradeNo, String alipayTradeNo, Map<String, String> params) {
        // 查询订单
        if (!stringRedisTemplate.hasKey(OrderConstant.SUBMIT_ORDER_KEY + outTradeNo)) {
            throw new ServiceException("订单不存在");
        }
        String orderStr = stringRedisTemplate.opsForValue().get(OrderConstant.SUBMIT_ORDER_KEY + outTradeNo);
        OrderEntity orderEntity = JSON.parseObject(orderStr, OrderEntity.class);

        if (orderEntity != null) {
            //修改redis订单支付状态
            orderEntity.setStatus(OrderStatusEnum.PAID.getCode());
            stringRedisTemplate.opsForValue().set(OrderConstant.SUBMIT_ORDER_KEY + outTradeNo, JSON.toJSONString(orderEntity));
            //支付宝交易凭证号
            orderEntity.setAlipayNo(alipayTradeNo);
            orderEntity.setPaymentTime(new Date());
            //1==>已支付
            orderEntity.setStatus(OrderStatusEnum.PAID.getCode());
//            this.updateById(orderEntity);
            //使用优惠券
            UpdateCouponHistoryParam param = new UpdateCouponHistoryParam();
            param.setCouponId(orderEntity.getCouponId());
            param.setOrderSn(orderEntity.getOrderSn());
            param.setUseType(1);
            couponRemoteService.updHistoryStatus(param);
            //生成交易流水单
            PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
            paymentInfoEntity.setOrderSn(orderEntity.getOrderSn());
            paymentInfoEntity.setOrderId(orderEntity.getId());
            paymentInfoEntity.setAlipayTradeNo(alipayTradeNo);
            paymentInfoEntity.setTotalAmount(orderEntity.getPayAmount());
            paymentInfoEntity.setSubject(params.get("subject"));
            paymentInfoEntity.setPaymentStatus("已支付");
            paymentInfoEntity.setCreateTime(new Date());
            paymentInfoService.save(paymentInfoEntity);
        }
    }


}
